/* components */
import WXSelectEnterPriseContact from '@src/component/common/BaseContact/WXSelectEnterPriseContact.vue'
import DepartmentAndUser from '@src/component/common/BaseContact/DepartmentAndUser.vue'
import Department from '@src/component/common/BaseContact/Department.vue'
/* enum */
import ComponentNameEnum from '@model/enum/ComponentNameEnum'
/* entity */
import LoginUser from '@model/entity/LoginUser/LoginUser'
import Tag from '@model/entity/Tag/Tag'
/* model */
import { BaseContactOptions, BaseContactSelectedData, BaseContactTypeEnum } from '@src/component/common/BaseContact/BaseContactModel'
/* util */
import fastCall from '@src/component/util/fastCall'
import Log from '@src/util/log'
import { destroyComponent } from '@src/util/dom'
import { isArray, isUndefined, isObject, isString, isEmpty } from '@src/util/type'
import { isSafeNumber, randomString } from 'pub-bbx-utils'
import { mount } from '@src/util/vue'
/* vue */
import Vue, { VueConstructor } from 'vue'
import { Component } from 'vue-property-decorator'
import VC from '@model/VC'
import MsgModel from '@model/MsgModel'

const DepartmentAndUserComponent = Vue.extend(DepartmentAndUser)

type BaseContactResult = {
  users?: LoginUser[]
}

const CancelMessageData: MsgModel<BaseContactResult> = { status: 1, message: 'cancel', data: {}, succ: false, success: false }
const DestroyMessageData: MsgModel<BaseContactResult> = { status: 1, message: 'cancel', data: {}, succ: false, success: false }

function choose(type = BaseContactTypeEnum.Department, options: BaseContactOptions = {}): Promise<MsgModel<BaseContactResult>> {
  Log.info(type, 'type', choose.name)
  if(type == BaseContactTypeEnum.Department || type == BaseContactTypeEnum.Team) {
    // 目前后端个人授权选择外部联系人还没做好前端先隐藏
    // isQYWX && 个人联系人权限
    // if(isQYWX()) {
    //   return renderWXSelectEnterPriseContact(options)
    // } else {
      return renderDepartmentAndUserComponent(options)
    // }
  }
  
  if(type == BaseContactTypeEnum.DepartmentOnly) {
    return renderDepartmentComponent(options)
  }
  
  return Promise.reject(new Error('type is not supported'))
  
}

function renderWXSelectEnterPriseContact(options: BaseContactOptions) {
  const attrs = {
    props: buildWXSelectEnterPriseContactProps(options)
  }
  return (
    new Promise((resolve, reject) => {
      @Component({
        components: { [WXSelectEnterPriseContact.name]: WXSelectEnterPriseContact }
      })
      class WXSelectEnterPriseContactHOC extends VC {
        private successHandler(users: LoginUser[]) {
          resolve({ status: 0, data: users })
        }
        render() {
          return (
            <base-wx-contact-dept-user
              {...attrs}
              onSuccess={(users: LoginUser[]) => this.successHandler(users)}
            ></base-wx-contact-dept-user>
          )
        }
      }
      
      mount(WXSelectEnterPriseContactHOC, ComponentNameEnum.WXSelectEnterPriseContactHOC)
    })
  )
}

function renderDepartmentAndUserComponent(options: BaseContactOptions): Promise<MsgModel<BaseContactResult>> {
  const attrs = {
    props: buildDepartmentAndUserProps(options)
  }
  
  return (
    new Promise((resolve, reject) => {
      @Component({
        components: { [DepartmentAndUser.name]: DepartmentAndUser }
      })
      class DepartmentAndUserHOC extends VC {
        
        private pending: boolean = false
        
        private cancelHandler() {
          if(this.pending) return
          
          this.pending = true
          
          resolve(CancelMessageData)
        }
        
        private destroyHandler() {
          setTimeout(() => destroyComponent(this), 1500);
          resolve(DestroyMessageData)
        }
        
        private inputHandler(users: BaseContactResult) {
          if(this.pending) return
          
          this.pending = true
          
          resolve({ status: 0, data: users, succ: true, success: true })
        }
        
        render() {
          return (
            <base-contact-dept-user 
              {...attrs}
              onCancel={() => this.cancelHandler()}
              onDestroy={() => this.destroyHandler()}
              onInput={this.inputHandler}
            >
            </base-contact-dept-user>
          )
        }
      }
      
      mount(DepartmentAndUserHOC, ComponentNameEnum.DepartmentAndUserHOC)
    })
  )
}

function renderDepartmentComponent(options: BaseContactOptions): Promise<MsgModel<BaseContactResult>> {  
  const attrs = {
    props: buildDepartmentProps(options)
  }
  
  return (
    new Promise((resolve, reject) => {
      @Component({
        components: { [Department.name]: Department }
      })
      class DepartmentHOC extends VC {
        
        private pending: boolean = false
        
        private cancelHandler() {
          if(this.pending) return
          
          this.pending = true
          
          resolve(CancelMessageData)
        }
        
        private destroyHandler() {
          setTimeout(() => destroyComponent(this), 1500)
          resolve(DestroyMessageData)
        }
        
        private inputHandler(users: BaseContactResult) {
          if(this.pending) return
          
          this.pending = true
          
          resolve({ status: 0, data: users, succ: true, success: true })
        }
        
        render() {
          return (
            <base-contact-department 
              {...attrs}
              onDestroy={() => this.destroyHandler()}
              onCancel={() => this.cancelHandler()}
              onInput={this.inputHandler}
            >
            </base-contact-department>
          )
        }
      }
      
      mount(DepartmentHOC, ComponentNameEnum.DepartmentHOC)
    })
  )
}

function buildDepartmentProps(options: BaseContactOptions) {
  let selectedDepts: Tag[] = []
  
  if(isArray(options?.selectedDepts)) {
    selectedDepts = options.selectedDepts as Tag[]
  }
  
  return {
    max: getOptionsMax(options),
    selectedDepts,
    seeAllOrg: getOptionsSeeAllOrg(options),
    title: getOptionsTitle(options)
  }
}

function buildWXSelectEnterPriseContactProps(options: BaseContactOptions) {
  const max = getOptionsMax(options)
  return {
    selectedUser: getOptionsSelectedUser(options, max),
    selectedDepts: getOptionsSelectedDepts(options),
    max
  }
}

function buildDepartmentAndUserProps(options: BaseContactOptions) {
  const max = getOptionsMax(options)
  
  return {
    title: getOptionsTitle(options),
    selectedUser: getOptionsSelectedUser(options, max),
    selectedDepts: getOptionsSelectedDepts(options),
    max,
    showTaskCount: getOptionsShowTaskCount(options),
    showUserState: getOptionsShowUserState(options),
    // 是否显示定位信息
    showLocation: getOptionsShowLocation(options),
    lat: getOptionsLatitude(options),
    lng: getOptionsLongitude(options),
    action: getOptionsAction(options),
    showDeptCheckbox: getOptionsShowDeptCheckbox(options) || getOptionsShowTeamCheckbox(options),
    CheckDeptshowUser: getOptionsCheckDeptshowUser(options),
    // 是否 只可见本团队成员
    seeAllOrg: getOptionsSeeAllOrg(options),
    departShow: options?.departShow || undefined,
    // 是否显示离职人员
    showDeleteUser: options.showDeleteUser || false,
    // 是否显示离职人员
    haveRole: options.haveRole || false,
    top: isUndefined(options?.top) ? undefined : options.top,
    unique: isUndefined(options?.unique) ? undefined : options.unique,
    options: options?.options ? options.options : getDefaultOptions(),
    from: options?.from,
    typeServiceProvider: options?.typeServiceProvider, // 服务商 控制左边树 【0组织架构】 【1服务商】 【''全部】 默认和之前逻辑一样
    isJudge: options?.isJudge, // 是否验证被选中的人是不是主管  
    isNothing: options?.isNothing, // 高级搜索是否添加 无 字段
    canDel: options?.canDel, // 是否可以删除选中的人
    isUserGuide: getOptionsIsUserGuide(options),
    isCalendar: options?.isCalendar, // 是否是日历模块
    calendarAction: options?.calendarAction, // 日历左侧树接口
    calendarSeeAllOrg: options?.calendarSeeAllOrg, // 日历左侧树接口
    isNeedEmail:options?.isNeedEmail||false, //是否需要邮箱字段
    isShowTag: options?.isShowTag || false, //是否只显示tag
    showNoRole: options?.showNoRole || false, // 分配角色添加成员要显示没角色人员
    ...(options?.authKey ? {authKey:options.authKey} : {})
  }
}

function getDefaultOptions() {
  return {
    id: `base-user-${randomString(4)}-${randomString(4)}`
  }
}

function getOptionsMax(options: BaseContactOptions): number {
  try {
    let max = options.max
    
    if (!max) return 0
    
    if (isString(max)) {
      max = parseInt(max as string)
    }
    
    if (isSafeNumber(max)) {
      return max as number
    }
    
    return 0
    
  } catch (error) {
    Log.error(error, getOptionsMax.name)
    return 0
  }
}

function getOptionsTitle(options: BaseContactOptions): string | undefined {
  return options?.title || undefined
}

function getOptionsSelectedUser(options: BaseContactOptions, max: number): LoginUser[] {
  // 是否只能选择一个用户
  const isOnlySelectOneUser = max === 1
  // 后端已经限制了人数，前端不应限制选人
  if (isArray(options?.selected)) {
    return isOnlySelectOneUser ? [] : options.selected as LoginUser[]
  }
  
  const baseContactSelectedData: BaseContactSelectedData = options?.selected as BaseContactSelectedData
  if (isObject(options?.selected)) {
    return isOnlySelectOneUser ? [] : (baseContactSelectedData?.users || [])
  }
  
  return []
}

function getOptionsShowTaskCount(options: BaseContactOptions): boolean {
  return options?.showTaskCount === true
}

function getOptionsShowUserState(options: BaseContactOptions): boolean {
  return options?.showUserState === true
}

function getOptionsSelectedDepts(options: BaseContactOptions): Tag[] {
  const isShowDeptCheckbox = getOptionsShowDeptCheckbox(options)
  const optionsSelected = options?.selected as BaseContactSelectedData
  const isObjectOptionsSelected = isObject(optionsSelected)
  
  if (isShowDeptCheckbox && !isEmpty(options.selectedDepts)) {
    return options.selectedDepts as Tag[]
  }
  
  if (isShowDeptCheckbox && isObjectOptionsSelected && !isEmpty(optionsSelected?.depts)) {
    return optionsSelected.depts as Tag[]
  }
  
  const isShowTeamCheckbox = getOptionsShowTeamCheckbox(options)
  
  if (isShowTeamCheckbox && !isEmpty(options.selectedTeams)) {
    return options.selectedTeams as Tag[]
  }
  
  if (isShowTeamCheckbox && isObjectOptionsSelected && !isEmpty(optionsSelected?.depts || optionsSelected?.teams)) {
    return (optionsSelected?.depts || optionsSelected?.teams) as Tag[]
  }
  
  return []
}

function getOptionsAction(options: BaseContactOptions): string {
  return options?.action || '/security/tag/userList'
}

function getOptionsShowLocation(options: BaseContactOptions): boolean {
  return Boolean(options?.allotMap)
}

function getOptionsLatitude(options: BaseContactOptions): string | number | undefined {
  return options?.lat || undefined
}

function getOptionsLongitude(options: BaseContactOptions): string | number | undefined {
  return options?.lng || undefined
}

function getOptionsShowDeptCheckbox(options: BaseContactOptions): boolean {
  return options?.showDeptCheckbox === true
}

function getOptionsCheckDeptshowUser(options: BaseContactOptions): boolean {
  return options?.CheckDeptshowUser === true
}

function getOptionsShowTeamCheckbox(options: BaseContactOptions): boolean {
  return options?.showTeamCheckbox === true
}

function getOptionsIsUserGuide(options: BaseContactOptions): boolean {
  return options?.isUserGuide === true
}

function getOptionsSeeAllOrg(options: BaseContactOptions): boolean {
  return Boolean(options?.seeAllOrg) || false
}

const BaseContact = {
  install(vue: VueConstructor) {
    fastCall(vue, 'contact', { choose })
  },
  namespace: 'contact',
  props: {
    choose
  }
}

export default BaseContact;
